﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;

namespace LegendHub.IO
{
    public class EntityHelper
    {
        public static object CreateListFromList(object oSource)
        {
            if (oSource == null)
            {
                return null;
            }
            var type = oSource.GetType();
            var obj = Activator.CreateInstance(type);
            var enumerator = (IEnumerator)type.GetMethod("GetEnumerator").Invoke(oSource, new object[0]);
            while (enumerator.MoveNext())
            {
                var obj1 = Activator.CreateInstance(enumerator.Current.GetType());
                DeepCopyObj(enumerator.Current, obj1);
                var method = type.GetMethod("Add");
                object[] objArray = { obj1 };
                method.Invoke(obj, objArray);
            }
            return obj;
        }

        public static List<TResult> DatabTableToList<TResult>(DataTable dt)
        where TResult : class, new()
        {
            var propertyInfos = new List<PropertyInfo>();
            var type = typeof(TResult);
            Array.ForEach(type.GetProperties(), p =>
            {
                if (dt.Columns.IndexOf(p.Name) != -1)
                {
                    propertyInfos.Add(p);
                }
            });
            var tResults = new List<TResult>();
            foreach (DataRow row in dt.Rows)
            {
                var tResult = Activator.CreateInstance<TResult>();
                propertyInfos.ForEach(p =>
                {
                    if (row[p.Name] == DBNull.Value) return;
                    if ((row[p.Name]) is long)
                        p.SetValue(tResult, Convert.ToInt32(row[p.Name]), null);
                    else
                        p.SetValue(tResult, row[p.Name], null);
                });
                tResults.Add(tResult);
            }
            return tResults;
        }

        public static void DatabTableToListVmModel<TResult, TResultModel>(DataTable dt, out List<TResult> oblistTResult, out List<TResultModel> oblistTResultModel)
            where TResult : class, new()
            where TResultModel : class, new()
        {
            var propertyInfos = new List<PropertyInfo>();
            var type = typeof(TResult);
            var type1 = typeof(TResultModel);
            var properties = type.GetProperties();
            var strs = properties.Select(t => t.Name).ToList();
            var propertyInfoArray = type1.GetProperties();
            var strs1 = propertyInfoArray.Select(t => t.Name).ToList();
            var properties1 = type.GetProperties();
            var array = properties1.Where(propertyInfo => !propertyInfo.PropertyType.Name.Contains("ZaoJia_")).ToArray();
            Array.ForEach(type1.GetProperties(), p =>
            {
                if (dt.Columns.IndexOf(p.Name) != -1)
                {
                    propertyInfos.Add(p);
                }
            });
            Array.ForEach(array, p =>
            {
                if (dt.Columns.IndexOf(p.Name) != -1)
                {
                    propertyInfos.Add(p);
                }
            });
            oblistTResultModel = new List<TResultModel>();
            oblistTResult = new List<TResult>();
            foreach (DataRow row in dt.Rows)
            {
                var tResultModel = Activator.CreateInstance<TResultModel>();
                var tResult = Activator.CreateInstance<TResult>();
                propertyInfos.ForEach(p =>
                {
                    if (row[p.Name] != DBNull.Value && strs1.Contains(p.Name))
                    {
                        p.SetValue(tResultModel, row[p.Name], null);
                    }
                });
                propertyInfos.ForEach(p =>
                {
                    if (row[p.Name] != DBNull.Value && strs.Contains(p.Name))
                    {
                        p.SetValue(tResult, row[p.Name], null);
                    }
                });
                oblistTResultModel.Add(tResultModel);
                oblistTResult.Add(tResult);
            }
        }

        public static void DeepCopyObj<T>(T oSource, T oNewObj)
        {
            if (oSource == null)
            {
                return;
            }
            if (oNewObj == null)
            {
                oNewObj = (T)Activator.CreateInstance(oSource.GetType());
            }
            var properties = oNewObj.GetType().GetProperties();
            foreach (var propertyInfo in properties)
            {
                if (propertyInfo.PropertyType.Name == "List`1" || propertyInfo.PropertyType.Name == "List")
                {
                    propertyInfo.SetValue(oNewObj, CreateListFromList(propertyInfo.GetValue(oSource, null)), null);
                }
                else if (propertyInfo.PropertyType.Namespace != "System")
                {
                    DeepCopyObj(propertyInfo.GetValue(oSource, null), propertyInfo.GetValue(oNewObj, null));
                }
                else
                {
                    propertyInfo.SetValue(oNewObj, propertyInfo.GetValue(oSource, null), null);
                }
            }
        }

        public static T DeepCopyObject<T>(T oSource)
        {
            var t = Activator.CreateInstance<T>();
            var properties = typeof(T).GetProperties();
            foreach (var propertyInfo in (properties.Where(memberInfo => memberInfo.DeclaringType == typeof (T))).Where(propertyInfo => propertyInfo.CanWrite))
            {
                propertyInfo.SetValue(t, propertyInfo.GetValue(oSource, null), null);
            }
            return t;
        }

        public static void DeepCopyObject<T>(T oSource, T newSource)
        {
            var properties = typeof(T).GetProperties();
            foreach (var propertyInfo in properties.Where(propertyInfo => propertyInfo.DeclaringType == typeof(T)).Where(propertyInfo => propertyInfo.CanWrite))
            {
                propertyInfo.SetValue(newSource, propertyInfo.GetValue(oSource, null), null);
            }
        }

        public static T DeepCopyObjectWithSerializable<T>(T oSource)
        {
            if (oSource == null)
            {
                return oSource;
            }
            if (!typeof(T).Attributes.HasFlag(TypeAttributes.Serializable))
            {
                return Activator.CreateInstance<T>();
            }
            var binaryFormatter = new BinaryFormatter();
            var memoryStream = new MemoryStream();
            binaryFormatter.Serialize(memoryStream, oSource);
            memoryStream.Position = 0L;
            var obj = binaryFormatter.Deserialize(memoryStream);
            memoryStream.Close();
            binaryFormatter = null;
            return (T)obj;
        }

        public static void DelayExecuteOnce(ref Timer ti, TimerCallback cb, object obj, Stopwatch st, int sec = 100)
        {
            if (!st.IsRunning)
            {
                st.Start();
            }
            st.Stop();
            if (st.ElapsedMilliseconds < sec && ti != null)
            {
                ti.Change(-1, -1);
            }
            ti = new Timer(cb, obj, sec, -1);
            st.Restart();
        }

        public static DataTable ListToDataTable(IEnumerable list)
        {
            var propertyInfos = new List<PropertyInfo>();
            var enumerable = list as object[] ?? list.Cast<object>().ToArray();
            var elementType = enumerable.AsQueryable().ElementType;
            var dataTable = new DataTable();
            Array.ForEach(elementType.GetProperties(), p =>
            {
                propertyInfos.Add(p);
                dataTable.Columns.Add(p.Name, p.PropertyType);
            });
            foreach (var obj in enumerable)
            {
                var value = dataTable.NewRow();
                propertyInfos.ForEach(p => value[p.Name] = p.GetValue(obj, null));
                dataTable.Rows.Add(value);
            }
            return dataTable;
        }

        public static DataTable ListToDataTable<TResult>(IEnumerable<TResult> value)
        where TResult : class
        {
            var propertyInfos = new List<PropertyInfo>();
            var type = typeof(TResult);
            var dataTable = new DataTable();
            Array.ForEach(type.GetProperties(), p =>
            {
                propertyInfos.Add(p);
                dataTable.Columns.Add(p.Name, p.PropertyType);
            });
            foreach (var tResult in value)
            {
                var dataRow = dataTable.NewRow();
                propertyInfos.ForEach(p => dataRow[p.Name] = p.GetValue(tResult, null));
                dataTable.Rows.Add(dataRow);
            }
            return dataTable;
        }

        /// <summary>
        /// 等待obj对象界面全部加载完
        /// </summary>
        /// <param name="uccontrol"></param>
        /// <param name="deep"></param>
        public static void OnAllLogicalTreeLoaded(DependencyObject uccontrol, int deep = 0)
        {
            if (deep > 6)
            {
                return;
            }
            if (uccontrol is UserControl)
            {
                var isLoaded = false;
                do
                {
                    uccontrol.Dispatcher.Invoke(new Action(() => isLoaded = (uccontrol as UserControl).IsLoaded), DispatcherPriority.Send);
                    Thread.Sleep(5);
                }
                while (!isLoaded);
            }
            var objs = new List<object>();
            uccontrol.Dispatcher.Invoke(new Action(() =>
            { objs.AddRange(LogicalTreeHelper.GetChildren(uccontrol).Cast<object>()); }), DispatcherPriority.Send);
            foreach (var obj1 in objs.OfType<DependencyObject>())
            {
                OnAllLogicalTreeLoaded(obj1, deep + 1);
            }
        }

        public static void SetValue<T>(T entity, PropertyInfo pi, string value)
        {
            var str = pi.PropertyType.ToString();
            switch (str)
            {
                case "System.DateTime":
                case "System.Nullable`1[System.DateTime]":
                    {
                        pi.SetValue(entity, Convert.ToDateTime(value), null);
                        return;
                    }
                case "System.Int16":
                case "System.Nullable`1[System.Int16]":
                    {
                        pi.SetValue(entity, Convert.ToInt16(value), null);
                        return;
                    }
                case "System.Int32":
                case "System.Nullable`1[System.Int32]":
                    {
                        pi.SetValue(entity, Convert.ToInt32(value), null);
                        return;
                    }
                case "System.Int64":
                case "System.Nullable`1[System.Int64]":
                    {
                        pi.SetValue(entity, Convert.ToInt64(value), null);
                        return;
                    }
                case "System.UInt64":
                case "System.Nullable`1[System.UInt64]":
                    {
                        pi.SetValue(entity, Convert.ToUInt64(value), null);
                        return;
                    }
                case "System.Byte[]":
                case "System.Nullable`1[System.Byte[]]":
                    {
                        pi.SetValue(entity, Convert.FromBase64String(value), null);
                        return;
                    }
                case "System.Decimal":
                case "System.Nullable`1[System.Decimal]":
                    {
                        pi.SetValue(entity, Convert.ToDecimal(value), null);
                        return;
                    }
                case "System.Double":
                case "System.Nullable`1[System.Double]":
                    {
                        pi.SetValue(entity, Convert.ToDouble(value), null);
                        return;
                    }
                case "System.Boolean":
                case "System.Nullable`1[System.Boolean]":
                    {
                        pi.SetValue(entity, Convert.ToBoolean(value), null);
                        return;
                    }
                case "System.Windows.Media.Color":
                    {
                        var strArrays = value.Split(',');
                        if (strArrays.Count() != 4)
                        {
                            pi.SetValue(entity, (value), null);
                            return;
                        }
                        pi.SetValue(entity, Color.FromArgb(Convert.ToByte(strArrays[0]), Convert.ToByte(strArrays[1]), Convert.ToByte(strArrays[2]), Convert.ToByte(strArrays[3])), null);
                        return;
                    }
                case "System.Windows.Visibility":
                    {
                        switch (value)
                        {
                            case "Visible":
                                pi.SetValue(entity, Visibility.Visible, null);
                                return;

                            case "Collapsed":
                                pi.SetValue(entity, Visibility.Collapsed, null);
                                return;
                        }
                        pi.SetValue(entity, Visibility.Hidden, null);
                        return;
                    }
                case "System.Single":
                case "System.Nullable`1[System.Single]":
                    {
                        pi.SetValue(entity, Convert.ToSingle(value), null);
                        return;
                    }
                case "System.Drawing.FontStyle":
                    {
                        pi.SetValue(entity, (FontStyle)Enum.Parse(typeof(FontStyle), value, true), null);
                        return;
                    }
            }
            pi.SetValue(entity, (value ?? ""), null);
        }

        public static void SetValueDefault<T>(T entity, PropertyInfo pi)
        {
            var str = pi.PropertyType.ToString();
            switch (str)
            {
                case "System.DateTime":
                case "System.Nullable`1[System.DateTime]":
                    {
                        pi.SetValue(entity, null, null);
                        return;
                    }
                case "System.Int16":
                case "System.Nullable`1[System.Int16]":
                case "System.Int32":
                case "System.Nullable`1[System.Int32]":
                case "System.Int64":
                case "System.Nullable`1[System.Int64]":
                case "System.UInt64":
                case "System.Nullable`1[System.UInt64]":
                case "System.Byte[]":
                case "System.Nullable`1[System.Byte[]]":
                case "System.Decimal":
                case "System.Nullable`1[System.Decimal]":
                case "System.Double":
                case "System.Nullable`1[System.Double]":
                case "System.Single":
                case "System.Nullable`1[System.Single]":
                    {
                        pi.SetValue(entity, 0, null);
                        return;
                    }
                case "System.Boolean":
                case "System.Nullable`1[System.Boolean]":
                    {
                        pi.SetValue(entity, Convert.ToBoolean(false), null);
                        return;
                    }
                case "System.Windows.Media.Color":
                    {
                        pi.SetValue(entity, Color.FromArgb(100, 100, 100, 100), null);
                        return;
                    }
                case "System.Windows.Visibility":
                    {
                        pi.SetValue(entity, Visibility.Collapsed, null);
                        return;
                    }
                case "System.String":
                    {
                        pi.SetValue(entity, "", null);
                        return;
                    }
            }
            throw new Exception("没有该类型的默认值！");
        }

        public static List<List<T>> SplitList<T>(IList<T> lst, int takecount)
        {
            var lists = new List<List<T>>();
            for (var i = 0; i < lst.Count; i = i + takecount)
            {
                var list = lst.Skip(i).Take(takecount).ToList();
                lists.Add(list);
            }
            return lists;
        }
    }
}